package br.com.lm.geral.util;

import br.com.lm.base.eao.EaoException;
import br.com.lm.entity.CtrlUsuario;
import br.com.lm.entity.CtrlObjetoAcesso;
import br.com.lm.entity.CtrlPerfilAcesso;
import br.com.lm.entity.CtrlPerfilAcessoPK;
import br.com.lm.sistema.eao.CtrlUsuarioEao;
import br.com.lm.sistema.eao.CtrlObjetoAcessoEao;
import java.io.Serializable;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.servlet.http.HttpSession;

public class GerenciamentoLoginBean implements Serializable {

    private static final long serialVersionUID = 1L;
    
    //Tipos de resource-bundle (I18N)
    private static final String LOGIN_RESOURCE_BUNDLE_VAR  = "msgLogin";
    private static final String SYSTEM_RESOURCE_BUNDLE_VAR = "msgPool";
    
    //Internacionalizacao de mensagens e retorno
    private MessageProvider messageProvider; 
    private String resourceBundleVar;
    FacesMessage facesMessage;  
    
    //Informacoes de Login
    private Map<CtrlPerfilAcessoPK, List<CtrlObjetoAcesso>> mapModuloObjAcesso;
    private CtrlUsuario usuarioAutenticado;

    /* -----------------------------------------------------------------------
     * Getter's e Setter's publicos 
     * ---------------------------------------------------------------------- */                
    public Map<CtrlPerfilAcessoPK, List<CtrlObjetoAcesso>> getMapModuloObjAcesso() {
        return mapModuloObjAcesso;
    }

    public void setMapModuloObjAcesso(Map<CtrlPerfilAcessoPK, List<CtrlObjetoAcesso>> mapModuloObjAcesso) {
        this.mapModuloObjAcesso = mapModuloObjAcesso;
    }

    public CtrlUsuario getUsuarioAutenticado() {
        return usuarioAutenticado;
    }

    public void setUsuarioAutenticado(CtrlUsuario usuarioAutenticado) {
        this.usuarioAutenticado = usuarioAutenticado;
    }
    
    public static CtrlUsuario getUsuarioAutenticadoSessao() {
        //Leitura de usuario autenticado gravado em sessao
        CtrlUsuario usuarioAutenticadoSessao = null;
        FacesContext ctx = FacesContext.getCurrentInstance();
        HttpSession sessao = (HttpSession) ctx.getExternalContext().getSession(false);        
        try {
            usuarioAutenticadoSessao = (CtrlUsuario)sessao.getAttribute("usuarioAutenticado");
        } catch (Exception ex){}
        return usuarioAutenticadoSessao;
    }

    public static Map<CtrlPerfilAcessoPK, List<CtrlObjetoAcesso>> getmapModuloObjAcessoSessao() {
        //Leitura objetos de acesso individuais para perfil
        Map<CtrlPerfilAcessoPK, List<CtrlObjetoAcesso>> mapModuloObjAcessoSessao = null;
        FacesContext ctx = FacesContext.getCurrentInstance();
        HttpSession sessao = (HttpSession) ctx.getExternalContext().getSession(false);        
        try {
            mapModuloObjAcessoSessao = (Map<CtrlPerfilAcessoPK, List<CtrlObjetoAcesso>>)sessao.getAttribute("mapModuloObjAcesso");
        } catch (Exception ex){}
        return mapModuloObjAcessoSessao;
    }
        
    /* -----------------------------------------------------------------------
     * Passo: [1 de 4] - Valida Login 
     * ---------------------------------------------------------------------- */            
    public FacesMessage validaLogin(String userName, String password) throws EaoException {
        facesMessage = null;  
        try {
            //Criptografa a password para comparacao
            Funcoes funcoes = new Funcoes();
            String criptPassword = funcoes.criptografaSenha(password);            
            
            //Obtem Dados de Usuario vs Perfil de Acesso
            String cSql = "from CtrlUsuario as o where o.codUsuario = '" + userName + "' and o.pswUsuario = '" + criptPassword + "'";            
            CtrlUsuarioEao usuarioEAO = CtrlUsuarioEao.getInstance();
                       
            List<CtrlUsuario> usuarioList = usuarioEAO.get(cSql);
            
            if (usuarioList != null && !usuarioList.isEmpty()) {
                usuarioAutenticado = usuarioList.get(0);
                //Obtem Objetos de autorizacao para Perfil de Acesso
                if (usuarioAutenticado != null && criptPassword.equals(usuarioAutenticado.getPswUsuario())) 
                    facesMessage = obtemPerfilAcesso();                
            }
        } 
        catch (Exception e) {
            //Erro de Sistema... Analisar Log do Servidor!
            resourceBundleVar = SYSTEM_RESOURCE_BUNDLE_VAR;
            System.out.println("Erro LoginBean: " + e.getLocalizedMessage());
            facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, "LoginBean:", getMessageI18N("system.E001"));
        }

        //Logon Ok, verifica situacao do usuario
        if (usuarioAutenticado != null) 
            facesMessage = validaUsuario();
        else 
        if (facesMessage == null) {
            //Credenciais invalidas
            resourceBundleVar = LOGIN_RESOURCE_BUNDLE_VAR;
            facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessageI18N("E001"), 
                                            MsgCtrlBean.getMessageFrmt(getMessageI18N("E002"), new String[]{userName}));
        }
        return facesMessage;
    }
        
    /* -----------------------------------------------------------------------
     * Passo: [2 de 4] - Obtem perfil de acesso
     * ---------------------------------------------------------------------- */                
    private FacesMessage obtemPerfilAcesso() {
        facesMessage = null;
        try {
            Collection<CtrlPerfilAcesso> perfisAcesso = usuarioAutenticado.getIdPerfil().getCtrlPerfilAcessoCollection();
            if (perfisAcesso != null && !perfisAcesso.isEmpty()) {             
                
                //Objeto individuais de autorizacao agregado ao perfil
                CtrlObjetoAcessoEao objetoAcessoEAO = CtrlObjetoAcessoEao.getInstance();    
                
                //Analisa o perfil para objetos individuais de acesso
                for (CtrlPerfilAcesso perfilAcesso: perfisAcesso) {
                    if (perfilAcesso.getIdObjAutoriz() != null && perfilAcesso.getIdObjAutoriz().intValue() > 0) {
                        
                        String cSql = "from CtrlObjetoAcesso as o WHERE o.ctrlObjetoAcessoPK.idObjAutoriz = " +
                                    perfilAcesso.getIdObjAutoriz().toString() + " and o.ctrlObjetoAcessoPK.idModulo = " + 
                                    perfilAcesso.getCtrlModuloItem().getIdModulo().toString();
                        
                        List<CtrlObjetoAcesso> lstObjetoAcesso = objetoAcessoEAO.get(cSql);
                        
                        if (lstObjetoAcesso != null && !lstObjetoAcesso.isEmpty()) {
                            //Salva objetos de acesso individuais
                            if (mapModuloObjAcesso == null)
                                mapModuloObjAcesso = new HashMap<CtrlPerfilAcessoPK, List<CtrlObjetoAcesso>>();
                            mapModuloObjAcesso.put(perfilAcesso.getCtrlPerfilAcessoPK(), lstObjetoAcesso);
                        }    
                    }
                }
            }                                
            else usuarioAutenticado = null;    
        }
        catch (Exception e) {
            //Erro de Sistema... Analisar Log do Servidor!
            resourceBundleVar = SYSTEM_RESOURCE_BUNDLE_VAR;
            System.out.println("Erro LoginBean(obtemPerfilAcesso): " + e.getLocalizedMessage());
            facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, "LoginBean[2]:", getMessageI18N("system.E001"));
        }        
        return facesMessage;
    }
    
    /* -----------------------------------------------------------------------
     * Passo: [3 de 4] - Valida status e perfil do usuario
     * ---------------------------------------------------------------------- */                    
    private FacesMessage validaUsuario() {
        resourceBundleVar = LOGIN_RESOURCE_BUNDLE_VAR;
        facesMessage = null;
        String mensagem;
        
        if ("B".equals(usuarioAutenticado.getStsUsuario().toString())) { 
            //Usuario bloqueado
            mensagem = MsgCtrlBean.getMessageFrmt(getMessageI18N("W002"), new String[]{getMessageI18N("I006")});
            facesMessage = new FacesMessage(FacesMessage.SEVERITY_WARN, null, mensagem);
        }    
        else 
        if ("D".equals(usuarioAutenticado.getStsUsuario().toString())) {
            //Usuario desativado
            mensagem = MsgCtrlBean.getMessageFrmt(getMessageI18N("W003"), new String[]{getMessageI18N("I006")});
            facesMessage = new FacesMessage(FacesMessage.SEVERITY_WARN, null, mensagem);
        }    
        else {
            Character stsPefil = usuarioAutenticado.getIdPerfil().getStsPerfil() == null ? 'L' : usuarioAutenticado.getIdPerfil().getStsPerfil();
            if (stsPefil.equals('B')) { 
                //Perfil Bloqueado
                facesMessage = new FacesMessage(FacesMessage.SEVERITY_WARN, usuarioAutenticado.getIdPerfil().getDscPerfil(), getMessageI18N("W004"));           
            }    
            else 
            if (stsPefil.equals('D')) { 
                //Perfil Desativado
                facesMessage = new FacesMessage(FacesMessage.SEVERITY_WARN, usuarioAutenticado.getIdPerfil().getDscPerfil(), getMessageI18N("W005"));           
            }    
        }
        return facesMessage;
    }

    /* -----------------------------------------------------------------------
     * Passo: [4 de 4] - Grava dados de sessao no sucesso do login
     *                   Transfere o controle para Home Page
     *                   Gera mensagem de boas vindas
     * ---------------------------------------------------------------------- */                        
    public FacesMessage sucessoLogin (boolean gravaDadosSessao, boolean redireciona) {
        FacesContext ctx = FacesContext.getCurrentInstance();
        facesMessage = null;
        try {
            if (gravaDadosSessao) {
                HttpSession session = (HttpSession) ctx.getExternalContext().getSession(true);
                //Grava dados de sessao do usuario autenticado
                session.setAttribute("usuarioAutenticado", usuarioAutenticado);
                session.setAttribute("mapModuloObjAcesso", this.mapModuloObjAcesso);
            }    
            
            //Redireciona controle de navegacao
            if (redireciona)
                ctx.getExternalContext().redirect(ctx.getExternalContext().getRequestContextPath() + "/home.jsf");
                    
        } catch (Exception e) {
            //Erro de Sistema... Analisar Log do Servidor!
            System.out.println("Erro LoginBean(sucessoLogin): " + e.getLocalizedMessage());
            resourceBundleVar = SYSTEM_RESOURCE_BUNDLE_VAR;            
            facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, "LoginBean[4]:", getMessageI18N("system.E001"));
       }
       return facesMessage; 
    }
         
    /* -----------------------------------------------------------------------
     * Passo: [1 de 1] - Altera senha de um usuario autenticado
     * ---------------------------------------------------------------------- */                        
    public FacesMessage alteraSenhaAntigaParaNovaSenha(String newPassword) throws EaoException {        
        facesMessage = null;
        resourceBundleVar = LOGIN_RESOURCE_BUNDLE_VAR;

        //Verifica se usuario esta autenticado para efetuar alteracao de senha    
        if (usuarioAutenticado == null) {
            //Credenciais invalidas ou nao efetuada - Dependencia do Passo: [1 de 4]
             facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, getMessageI18N("E001"), getMessageI18N("E002"));
             return facesMessage;
        }
        
        //Senha Alterada com sucesso
        facesMessage = new FacesMessage(FacesMessage.SEVERITY_INFO, usuarioAutenticado.getNomUsuario(), getMessageI18N("I019"));
        
        try {
            //Criptografa a password para comparacao
            Funcoes funcoes = new Funcoes();
            String criptPassword = funcoes.criptografaSenha(newPassword);
            
            CtrlUsuarioEao usuarioEAO = CtrlUsuarioEao.getInstance();
            
            usuarioAutenticado.setPswUsuario(criptPassword);
            usuarioEAO.edit(usuarioAutenticado);
         } 
        catch (Exception e) {
            //Erro de Sistema... Analisar Log do Servidor!
            System.out.println("Erro LoginBean(alteraSenhaAntigaParaNovaSenha): " + e.getLocalizedMessage());            
            resourceBundleVar = SYSTEM_RESOURCE_BUNDLE_VAR;
            facesMessage = new FacesMessage(FacesMessage.SEVERITY_ERROR, "LoginBean[5]:", getMessageI18N("system.E001"));
        }
        return facesMessage;
    }

    /* -----------------------------------------------------------------------
     * Passo: [1 de 1] - Obtem dados usuario (sem validacao de senha)
     * ---------------------------------------------------------------------- */                        
    public CtrlUsuario getCtrlUsuarioById(String codUsuario) throws EaoException {
        CtrlUsuarioEao usuarioEAO = CtrlUsuarioEao.getInstance();
        return usuarioEAO.getCtrlUsuarioById(codUsuario);
    }
    
    /* -----------------------------------------------------------------------
     * Passo: [1 de 1] - Atualização de colunas para o código de usuário
     * ---------------------------------------------------------------------- */                        
    public void updCtrlUsuarioById(String codUsuario, Map<String,Object> mapColVlr) throws EaoException {
        if (mapColVlr == null || mapColVlr.isEmpty()) {
            throw new RuntimeException("CTRL_USUARIO: Missing columns in field list");
        }
        //Gera Query para atualização
        StringBuilder sb = new StringBuilder();
        Set<Map.Entry<String, Object>> set = mapColVlr.entrySet();
        for (Iterator<Map.Entry<String, Object>> iter = set.iterator(); iter.hasNext();) {
            Map.Entry<String, Object> me = iter.next();
            if (sb.length() == 0)
                sb.append("UPDATE CtrlUsuario SET ");
            else sb.append(",");            
            sb.append(me.getKey());
            sb.append(" = ");
            if (me.getValue() instanceof Integer)
                sb.append(me.getValue().toString());
            else
            if (me.getValue() instanceof String  ||
                me.getValue() instanceof Character) {
                sb.append("'");
                sb.append(me.getValue().toString());
                sb.append("'");
            }    
            else {
               throw new RuntimeException("CTRL_USUARIO: Unknown column in field list");
            }
        }
        sb.append(" WHERE Cod_Usuario = ");
        sb.append("'");
        sb.append(codUsuario);
        sb.append("'");
        //Atualiza colunas da tabela de Usuário
        CtrlUsuarioEao usuarioEAO = CtrlUsuarioEao.getInstance();
        usuarioEAO.executeUpdate(sb.toString(),null, null);
    }
    
    /* -----------------------------------------------------------------------
     * Obtem a descricao da mensagem usando Internacionalizacao I18N
     * ---------------------------------------------------------------------- */                                
    private String getMessageI18N(String chaveMsg) {
        if (messageProvider == null  || !resourceBundleVar.equals(messageProvider.getResourceBundleVar()))
            messageProvider = new MessageProvider(resourceBundleVar);
        return messageProvider.getValueFromKey(chaveMsg);
    }
    
}